package com.huatai.datacenter.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huatai.common.util.StringUtil;
import com.huatai.datacenter.entity.CodeEntity;
import com.huatai.datacenter.entity.WordRequestLogEntity;
import com.huatai.datacenter.entity.datadesensitization.DesensitizationRuleEntity;
import com.huatai.datacenter.entity.datamodel.DataModelBaseEntity;
import com.huatai.datacenter.entity.datamodel.DataModelFieldEntity;
import com.huatai.datacenter.entity.dto.EncryDto;
import com.huatai.datacenter.entity.postdata.HttpRequestEntity;
import com.huatai.datacenter.mapper.DesensitizationRuleMapper;
import com.huatai.datacenter.mapper.HttpRequestMapper;
import com.huatai.datacenter.mapper.WordRequestLogMapper;
import com.huatai.datacenter.service.CodeService;
import com.huatai.datacenter.service.DataModelFieldService;
import com.huatai.datacenter.service.DesensitizationRuleService;
import com.huatai.datacenter.utils.EncryptionUtils;
import com.huatai.datacenter.utils.EncryptionUtilss;
import com.huatai.datacenter.utils.RSAUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author gusiyi
 * @version 1.0
 * @className DesensitizationRuleServiceImpl
 * @description 描述：
 * @date 2023/6/12 15:40
 */
@Service
public class DesensitizationRuleServiceImpl extends ServiceImpl<DesensitizationRuleMapper, DesensitizationRuleEntity> implements DesensitizationRuleService {

	@Autowired
	private CodeService codeService;

	@Autowired
	private DataModelFieldService dataModelFieldService;
	@Autowired
	private DesensitizationRuleMapper desensitizationRuleMapper;
	@Autowired
	private HttpRequestMapper httpRequestMapper;

	@Override
	public Page<DesensitizationRuleEntity> getRuleList(DesensitizationRuleEntity desensitizationRuleEntity) {
		LambdaQueryWrapper<DesensitizationRuleEntity> ruleQuery = Wrappers.lambdaQuery();
		ruleQuery
			.eq(DesensitizationRuleEntity::getDeleted, false)
			.like(StringUtil.isNotBlank(desensitizationRuleEntity.getDesensitizationName()), DesensitizationRuleEntity::getDesensitizationName, desensitizationRuleEntity.getDesensitizationName())
			.orderByDesc(DesensitizationRuleEntity::getUpdateTime);
		return page(new Page<>(desensitizationRuleEntity.getPageIndex(), desensitizationRuleEntity.getPageSize()), ruleQuery);
	}

	@Override
	public Map<String, Object> getRuleListByDataModelIdAndFieldName(DesensitizationRuleEntity desensitizationRuleEntity) {
		LambdaQueryWrapper<DesensitizationRuleEntity> ruleQuery = Wrappers.lambdaQuery();
		ruleQuery
			.eq(DesensitizationRuleEntity::getDeleted, false)
			.eq(desensitizationRuleEntity.getDataModelId() != null, DesensitizationRuleEntity::getDataModelId, desensitizationRuleEntity.getDataModelId());
		ruleQuery.orderByDesc(DesensitizationRuleEntity::getUpdateTime);
		List<DesensitizationRuleEntity> ruleList = list(ruleQuery);
		Map<String, Object> resultMap = new LinkedHashMap<>();
		if (desensitizationRuleEntity.getDesensitizationObj()) {
			resultMap.put("obj", ruleList);
			return resultMap;
		} else {
			LambdaQueryWrapper<DataModelFieldEntity> fieldQuery = Wrappers.lambdaQuery();
			fieldQuery
				.eq(DataModelBaseEntity::getDeleted, false)
				.eq(DataModelFieldEntity::getDataModelId, desensitizationRuleEntity.getDataModelId());
			List<DataModelFieldEntity> fieldList = dataModelFieldService.list(fieldQuery);
			Map<String, List<DataModelFieldEntity>> groupByFieldName = fieldList.stream().collect(Collectors.groupingBy(DataModelFieldEntity::getFieldName));
			Set<String> fieldSet = groupByFieldName.keySet();
			for (String key : fieldSet) {
				List<DesensitizationRuleEntity> resultList = new ArrayList<>(ruleList.size());
				for (DesensitizationRuleEntity ruleEntity : ruleList) {
					if (key.equals(ruleEntity.getDesensitizationFieldName())) {
						resultList.add(ruleEntity);
					}
				}
				resultMap.put(key, resultList);
			}
			return resultMap;
		}
	}

	@Override
	public boolean deleteByIds(List<DesensitizationRuleEntity> desensitizationRuleEntity) {
		for (DesensitizationRuleEntity ruleEntity : desensitizationRuleEntity) {
			ruleEntity.setDeleted(true);
		}
		return updateBatchById(desensitizationRuleEntity);
	}

	@Override
	public Map<String, Object> desensitizationData(JSONObject key, Long[] desensitizationRuleIds, String serviceDataStr) {
		Map<String, Object> reusltMap = new HashMap<>(2);
		reusltMap.put("beforeDesensitization", serviceDataStr);
		JSONArray serviceDataArray = JSONArray.parseArray(serviceDataStr);
		LambdaQueryWrapper<DesensitizationRuleEntity> ruleQuery = Wrappers.lambdaQuery();
		ruleQuery
			.eq(DesensitizationRuleEntity::getDeleted, false)
			.in(DesensitizationRuleEntity::getId, desensitizationRuleIds);
		List<DesensitizationRuleEntity> ruleList = list(ruleQuery);
		LambdaQueryWrapper<CodeEntity> codeQuery = Wrappers.lambdaQuery();
		LambdaQueryWrapper<CodeEntity> desensitizationRuleType = codeQuery
			.eq(CodeEntity::getDeleted, false)
			.eq(CodeEntity::getType, "desensitizationRuleType");
		List<CodeEntity> codeList = codeService.list(desensitizationRuleType);
		Map<Integer, List<CodeEntity>> parentNumMap = codeList.stream().collect(Collectors.groupingBy(CodeEntity::getParentNum));
		boolean allDesensitization = false;
		for (int i = 0; i < serviceDataArray.size(); i++) {
			JSONObject serviceDataJson = serviceDataArray.getJSONObject(i);
			for (DesensitizationRuleEntity desensitizationRuleEntity : ruleList) {
				//对字段进行脱敏
				String desensitizationFieldName = desensitizationRuleEntity.getDesensitizationFieldName();
				if (StringUtil.isNotBlank(desensitizationFieldName)) {
					String fieldValue = serviceDataJson.getString(desensitizationFieldName);
					String dealValue = dealFieldData(key, fieldValue, desensitizationRuleEntity.getDesensitizationTypeNum(), desensitizationRuleEntity.getDesensitizationRuleTypeNum(), parentNumMap);
					serviceDataJson.put(desensitizationFieldName, dealValue);
				} else {
					allDesensitization = true;
					break;
				}
			}
			if (allDesensitization) {
				break;
			}
		}
		reusltMap.put("afterDesensitization", serviceDataArray.toJSONString());
		if (allDesensitization) {
			//对整个数据进行脱敏
			String resultString = dealObjectData(key, serviceDataStr, ruleList.get(0), parentNumMap);
			reusltMap.put("afterDesensitization", resultString);
		}
		return reusltMap;
	}

	@Autowired
	private WordRequestLogMapper wordRequestLogMapper;
	/**
	 * 描述: 数据脱敏（对象）
	 * 创建人: gaowengui
	 * 创建时间: 2025-05-30 12:0:00
	 * @param key desensitizationRuleIds  serviceDataStr
	 * @return
	 * @throws
	 **/
	@Override
	public EncryDto desensitizationDataCopy(JSONObject key, Long[] desensitizationRuleIds, String serviceDataStr,Long requrtId) {
		Map<String,Object> reusltMap = new HashMap<>(2);
		reusltMap.put("beforeDesensitization",serviceDataStr);
		JSONArray serviceDataArray = JSONArray.parseArray(serviceDataStr);
		LambdaQueryWrapper<DesensitizationRuleEntity> ruleQuery = Wrappers.lambdaQuery();
		ruleQuery
				.eq(DesensitizationRuleEntity::getDeleted,false)
				.in(DesensitizationRuleEntity::getId,desensitizationRuleIds);
		List<DesensitizationRuleEntity> ruleList = list(ruleQuery);
		LambdaQueryWrapper<CodeEntity> codeQuery = Wrappers.lambdaQuery();
		LambdaQueryWrapper<CodeEntity> desensitizationRuleType = codeQuery
				.eq(CodeEntity::getDeleted, false)
				.eq(CodeEntity::getType, "desensitizationRuleType");
		List<CodeEntity> codeList = codeService.list(desensitizationRuleType);
		Map<Integer, List<CodeEntity>> parentNumMap = codeList.stream().collect(Collectors.groupingBy(CodeEntity::getParentNum));
		boolean allDesensitization = false;
		String dealValue = null;
		JSONObject DATAJSON = null;
		for (int i = 0; i < serviceDataArray.size(); i++) {
			WordRequestLogEntity wordRequestLogEntity = new WordRequestLogEntity();
			JSONObject serviceDataJson = serviceDataArray.getJSONObject(i);
			DATAJSON = serviceDataArray.getJSONObject(i);
			for (DesensitizationRuleEntity desensitizationRuleEntity : ruleList) {
				//对字段进行脱敏
				String desensitizationFieldName = desensitizationRuleEntity.getDesensitizationFieldName();

					wordRequestLogEntity.setRequestLogId(String.valueOf(requrtId));
					wordRequestLogEntity.setOrgiData(String.valueOf(DATAJSON.get("contact")));
					wordRequestLogEntity.setRemark(desensitizationRuleEntity.getDesensitizationRuleTypeName());
					wordRequestLogEntity.setCreateTime(LocalDateTime.now());

				if (StringUtil.isNotBlank(desensitizationFieldName)){
					String fieldValue = serviceDataJson.getString(desensitizationFieldName);
					 dealValue = dealFieldData(key,fieldValue,desensitizationRuleEntity.getDesensitizationTypeNum(),desensitizationRuleEntity.getDesensitizationRuleTypeNum(),parentNumMap);

					 wordRequestLogEntity.setNowData(dealValue);
					 serviceDataJson.put(desensitizationFieldName,dealValue);
				}else {
					allDesensitization = true;
					break;
				}
				wordRequestLogMapper.insert(wordRequestLogEntity);
			}

			if (allDesensitization){
				break;
			}
		}
		reusltMap.put("afterDesensitization",serviceDataArray.toJSONString());
		if (allDesensitization){
			//对整个数据进行脱敏
			String resultString = dealObjectData(key,serviceDataStr,ruleList.get(0),parentNumMap);
			reusltMap.put("afterDesensitization",resultString);
		}
		byte[] iv = EncryptionUtilss.generateIV();
		SecretKeySpec secretKey = EncryptionUtilss.generateAESKeys();
		String s = JSONObject.toJSONString(reusltMap);
		String s1 ="";
		try {
			s1 = EncryptionUtilss.encryptWithAES(s, secretKey, iv);
			System.out.println("s1 = " + s1);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		System.out.println("s1 = " + s1);
		//reusltMap.put("jiemidata",aesDecrypt);
		EncryDto encryDto = new EncryDto();
		encryDto.setEncryStr(s1);
		encryDto.setSecretKeySpec(secretKey);
		encryDto.setIv(iv);
		return encryDto;
	}

	/**
	 * @param key
	 * @param desensitizationRuleIds
	 * @param serviceDataStr
	 * @return
	 * @author gaowengui
	 * @time 2025-06-04
	 */
	@Override
	public Map<String, Object> desensitizationDatas(JSONObject key, Long[] desensitizationRuleIds, String serviceDataStr) {
		LambdaQueryWrapper<DesensitizationRuleEntity> ruleQuery = Wrappers.lambdaQuery();
		ruleQuery
			.eq(DesensitizationRuleEntity::getDeleted, false)
			.in(DesensitizationRuleEntity::getId, desensitizationRuleIds);
		List<DesensitizationRuleEntity> desensitizationRuleEntities = desensitizationRuleMapper.selectList(ruleQuery);

		for (int i = 0; i < desensitizationRuleEntities.size(); i++) {
			DesensitizationRuleEntity desensitizationRuleEntity = desensitizationRuleEntities.get(i);
			Long dataModelId = desensitizationRuleEntity.getDataModelId();
			LambdaQueryWrapper<HttpRequestEntity> modelQuery = Wrappers.lambdaQuery();
			modelQuery
				.eq(HttpRequestEntity::getModelId, dataModelId)
				.eq(HttpRequestEntity::getStatus, 0);

			List<HttpRequestEntity> httpRequestEntities = httpRequestMapper.selectList(modelQuery);
			for (int j = 0; j < httpRequestEntities.size(); j++) {
				HttpRequestEntity httpRequestEntity = httpRequestEntities.get(i);
				String tableName = httpRequestEntity.getTableName();

			}
		}

		Map<String, Object> reusltMap = new HashMap<>(2);
		reusltMap.put("beforeDesensitization", serviceDataStr);
		JSONArray serviceDataArray = JSONArray.parseArray(serviceDataStr);

		List<DesensitizationRuleEntity> ruleList = list(ruleQuery);
		LambdaQueryWrapper<CodeEntity> codeQuery = Wrappers.lambdaQuery();
		LambdaQueryWrapper<CodeEntity> desensitizationRuleType = codeQuery
			.eq(CodeEntity::getDeleted, false)
			.eq(CodeEntity::getType, "desensitizationRuleType");
		List<CodeEntity> codeList = codeService.list(desensitizationRuleType);
		Map<Integer, List<CodeEntity>> parentNumMap = codeList.stream().collect(Collectors.groupingBy(CodeEntity::getParentNum));
		boolean allDesensitization = false;
		for (int i = 0; i < serviceDataArray.size(); i++) {
			JSONObject serviceDataJson = serviceDataArray.getJSONObject(i);
			for (DesensitizationRuleEntity desensitizationRuleEntity : ruleList) {
				//对字段进行脱敏
				String desensitizationFieldName = desensitizationRuleEntity.getDesensitizationFieldName();
				if (StringUtil.isNotBlank(desensitizationFieldName)) {
					String fieldValue = serviceDataJson.getString(desensitizationFieldName);
					String dealValue = dealFieldData(key, fieldValue, desensitizationRuleEntity.getDesensitizationTypeNum(), desensitizationRuleEntity.getDesensitizationRuleTypeNum(), parentNumMap);
					serviceDataJson.put(desensitizationFieldName, dealValue);
				} else {
					allDesensitization = true;
					break;
				}
			}
			if (allDesensitization) {
				break;
			}
		}
		reusltMap.put("afterDesensitization", serviceDataArray.toJSONString());
		if (allDesensitization) {
			//对整个数据进行脱敏
			String resultString = dealObjectData(key, serviceDataStr, ruleList.get(0), parentNumMap);
			reusltMap.put("afterDesensitization", resultString);
		}
		return reusltMap;
	}

	/**
	 * 对整个数据进行脱敏
	 *
	 * @param keyJson
	 * @param serviceDataStr
	 * @param desensitizationRuleEntity
	 * @param parentNumMap
	 * @return
	 */
	private String dealObjectData(JSONObject keyJson, String serviceDataStr, DesensitizationRuleEntity desensitizationRuleEntity, Map<Integer, List<CodeEntity>> parentNumMap) {
		Integer desensitizationTypeNum = desensitizationRuleEntity.getDesensitizationTypeNum();
		Integer desensitizationRuleTypeNum = desensitizationRuleEntity.getDesensitizationRuleTypeNum();
		switch (desensitizationTypeNum) {
			case 1:
				return serviceDataStr;
			case 2:
				return serviceDataStr;
			case 3: {
				List<CodeEntity> codeEntities = parentNumMap.get(desensitizationTypeNum);
				for (CodeEntity codeEntity : codeEntities) {
					if (desensitizationRuleTypeNum.equals(codeEntity.getNum())) {
						String algorithm = codeEntity.getExtend();
						try {
							return EncryptionUtils.encrypt(serviceDataStr, keyJson.getString(algorithm + "Key"), algorithm);
						} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
								 InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException e) {
							e.printStackTrace();
						}
					}
				}
				return serviceDataStr;
			}
			case 4: {
				List<CodeEntity> codeEntities = parentNumMap.get(desensitizationTypeNum);
				for (CodeEntity codeEntity : codeEntities) {
					if (desensitizationRuleTypeNum.equals(codeEntity.getNum())) {
						String algorithm = codeEntity.getExtend();
						if ("RSA".equals(algorithm)) {
							byte[] publicKeyBytes = Base64.getDecoder().decode(keyJson.getString(algorithm + "PublicKey"));
							PublicKey publicKey = null;
							try {
								publicKey = RSAUtils.getPublicKey(publicKeyBytes);
								return RSAUtils.encrypt(serviceDataStr, publicKey);
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					}
				}
				return serviceDataStr;
			}
			default:
				return serviceDataStr;
		}
	}

	/**
	 * 根据脱敏类型与脱敏规则对字段数据进行脱敏
	 *
	 * @param keyJson                    加密密钥对象
	 * @param fieldValue
	 * @param desensitizationTypeNum
	 * @param desensitizationRuleTypeNum
	 * @param parentNumMap
	 * @return
	 */
	private String dealFieldData(JSONObject keyJson, String fieldValue, Integer desensitizationTypeNum, Integer desensitizationRuleTypeNum, Map<Integer, List<CodeEntity>> parentNumMap) {
		String resultString = fieldValue;
		List<CodeEntity> codeEntities = parentNumMap.get(desensitizationTypeNum);
		switch (desensitizationTypeNum) {
			case 1: {
				//字符串截取替换
				for (CodeEntity codeEntity : codeEntities) {
					if (desensitizationRuleTypeNum.equals(codeEntity.getNum())) {
						String extend = codeEntity.getExtend();
						String[] extendSplit = extend.split("/");
						int start = Integer.parseInt(extendSplit[1]);
						int end = Integer.parseInt(extendSplit[2]);
						if (StringUtils.isNotEmpty(extendSplit[0])) {
							int dataSplitIndex = fieldValue.indexOf(extendSplit[0]) + 1;
							start = dataSplitIndex + start;
							end = dataSplitIndex + end;
						}
						resultString = StrUtil.hide(fieldValue, start, end);
						break;
					}
				}
				break;
			}
			case 2: {
				//正则表达式替换类
				for (CodeEntity codeEntity : codeEntities) {
					if (desensitizationRuleTypeNum.equals(codeEntity.getNum())) {
						String extend = codeEntity.getExtend();
						String[] regexInfo = extend.split("/");
						resultString = fieldValue.replaceAll(regexInfo[0], regexInfo[1]);
					}
				}
				break;
			}
			case 3: {
				//对称加密类
				for (CodeEntity codeEntity : codeEntities) {
					if (desensitizationRuleTypeNum.equals(codeEntity.getNum())) {
						String algorithm = codeEntity.getExtend();
						try {
							resultString = EncryptionUtils.encrypt(fieldValue, keyJson.getString(algorithm + "Key"), algorithm);
						} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
								 InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException e) {
							e.printStackTrace();
						}
					}
				}
				break;
			}
			case 4: {
				//非对称加密类
				for (CodeEntity codeEntity : codeEntities) {
					if (desensitizationRuleTypeNum.equals(codeEntity.getNum())) {
						byte[] publicKeyBytes = Base64.getDecoder().decode(keyJson.getString(codeEntity.getExtend() + "PublicKey"));
						try {
							//公钥加密
							PublicKey publicKey = RSAUtils.getPublicKey(publicKeyBytes);
							resultString = RSAUtils.encrypt(fieldValue, publicKey);
						} catch (Exception e) {
							e.printStackTrace();
						}
						break;
					}
				}
				break;
			}
			default: {
				break;
			}
		}
		return resultString;
	}


}
